package mac5789.phase;

import java.util.HashMap;
import java.util.Map;

/**
 * Medidor de satisfatibilidade que delega a medição e mantém um cache, evitando consultas repetidas.
 * @author lundberg
 *
 */
public class CachingMeasurer implements SatisfiabilityMeasurer {
	private final SatisfiabilityMeasurer delegate;
	
	private final Map<MeasurementKey, Double> cache = new HashMap<MeasurementKey, Double>();

	public CachingMeasurer(SatisfiabilityMeasurer delegate) {
		super();
		this.delegate = delegate;
	}

	@Override
	public double measure(int nVariables, int nClauses) {
		MeasurementKey key = new MeasurementKey(nVariables, nClauses);
		if(!cache.containsKey(key)) {
			double measurement = delegate.measure(nVariables, nClauses);
			print(String.format("Medição feita para problemas de %s variáveis e %s cláusulas: %s", nVariables, nClauses, measurement));
			cache.put(key, measurement);
		}
		return cache.get(key);
	}
	
	public static class MeasurementKey {
		private final int nVariables;
		
		private final int nClauses;

		public MeasurementKey(int nVariables, int nClauses) {
			super();
			this.nVariables = nVariables;
			this.nClauses = nClauses;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + nClauses;
			result = prime * result + nVariables;
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			MeasurementKey other = (MeasurementKey) obj;
			if (nClauses != other.nClauses)
				return false;
			if (nVariables != other.nVariables)
				return false;
			return true;
		}
	}

	private void print(String msg) {
		System.out.println(msg);	
	}
}
